#include "Subida.h"

#include "signalHandlers/EXITCHILD_Handler.h"

Subida::Subida() {

}

Subida::~Subida() {
}

void Subida::publicarArchivos()
{
	int pid = fork();
	if (pid == 0) {

		SignalHandler::getInstance()->registrarHandler ( EXITCHILD_SIGNAL, Usuario::getInstance()->getExitChildHandler() );

		SolicitudDescargaType solicitud = Entorno::getInstance()->consultarSolicitudPublicarPara(Usuario::getInstance()->getId());

		stringstream logstream;
		logstream << "Inicializando subida Lista archivos. Solicitante: " << solicitud.idUsuarioDescarga << ";  Solicitado: " << solicitud.idUsuarioComparte << ";  Id solicitud: " << solicitud.idDescarga;
		Log::getInstance()->log(logstream.str());

		list<string> archivosCompartidos = Usuario::getInstance()->misArchivosCompartidos();

		list<string>::iterator itBeg = archivosCompartidos.begin();
		list<string>::iterator itBack = archivosCompartidos.end();
		stringstream sstream;
		for(;itBeg != itBack; itBeg++)
			sstream << *itBeg << endl;
		string str = sstream.str();

		string fifoFile = FIFO_DESCARGA_PATH;
		fifoFile += solicitud.idDescarga;
		Fifo canal (fifoFile.c_str());

		char * cstr = new char [str.size()+1];
		strcpy(cstr,str.c_str());
		cstr[str.size()] = '\0';

		canal.escribir( cstr , str.size());

		delete []cstr;
		kill(getpid(),EXITCHILD_SIGNAL);
		stringstream logstream2;
		logstream2 << "Listado compartido. Solicitante: " << solicitud.idUsuarioDescarga << ";  Solicitado: " << solicitud.idUsuarioComparte << ";  Id descarga: " << solicitud.idDescarga;
		Log::getInstance()->log(logstream2.str());
	}
}

void Subida::compartirArchivoPara(int usuarioId)
{
	// TODO: Refactorizar en metodos mas pequeños.
	// TODO: aplicar protocolo de inicio y fin de archivo. controlar size.
	SolicitudDescargaType solicitud = Entorno::getInstance()->consultarSolicitudDescargaPara(usuarioId);

	try {
		int pid = fork();

		if (pid == 0) {
			SignalHandler::getInstance()->registrarHandler ( EXITCHILD_SIGNAL, Usuario::getInstance()->getExitChildHandler() );

			stringstream logStream;
			logStream << "Inicializando subida archivo. Solicitante: " << solicitud.idUsuarioDescarga << ";  Solicitado: " << solicitud.idUsuarioComparte << ";  Id solicitud: " << solicitud.idDescarga;
			Log::getInstance()->log(logStream.str());

			if (!fileExists(solicitud.pathArchivo)) {
				throw new DescargaFallidaException((char*)"No se encuentra el archivo.");
			}

			list<string> archivosCompartidos = Usuario::getInstance()->misArchivosCompartidos();
			list<string>::iterator itBeg = archivosCompartidos.begin();
			list<string>::iterator itBack = archivosCompartidos.end();
			bool todaviaComparte = false;
			for(;itBeg != itBack && !todaviaComparte; itBeg++) {
				if ((*itBeg).compare(solicitud.pathArchivo) == 0) {
					todaviaComparte = true;
				}
			}

			char* buffer;
			int length;

			if (todaviaComparte) {
				// leo el archivo a transferir
				ifstream stream;
				stream.open(solicitud.pathArchivo, fstream::in);

				// obtengo la longitud del archivo para usar en el protocolo
				stream.seekg (0, ios::end);
				length = stream.tellg();
				stream.seekg (0, ios::beg);

				buffer = new char[length+1];
				stream.read (buffer,length);
				stream.close();
				buffer[length] = '\0';
			} else {
				length = 1;
				buffer = new char[length];
				buffer[0] = '\0';
			}

			// escribo el FIFO de transferencia
			string fifoFile = FIFO_DESCARGA_PATH;
			fifoFile += solicitud.idDescarga;
			Fifo canal (fifoFile.c_str());

			canal.escribir(buffer, length);

			delete [] buffer;

			kill(getpid(),EXITCHILD_SIGNAL);
			stringstream logstream;
			logstream << "Archivo compartido. Solicitante: " << solicitud.idUsuarioDescarga << ";  Solicitado: " << solicitud.idUsuarioComparte << ";  Id solicitud: " << solicitud.idDescarga;
			Log::getInstance()->log(logstream.str());
		} else {
			Usuario::getInstance()->registrarSubida(pid);
		}
	} catch(DescargaFallidaException e) {
		stringstream sstream;
		sstream << "Error Subida. Solicitante: " << solicitud.idUsuarioDescarga << ";  Solicitado: " << solicitud.idUsuarioComparte << ";  Id solicitud: " << solicitud.idDescarga;
		sstream << "; ERROR: " << e.what();
		Log::getInstance()->log(sstream.str());
	}
}
